﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using FilterData;
using Common;
using System.Collections;

namespace LoginServer
{
    public partial class User
    {
        public PlayerInfo info { get; set; }
        
        Socket client;
        IPAddress ip;
        int port;
        bool isPing;

        byte[] buffer = new byte[1024];
        byte[] dataSend;
        byte[] dataReceive;
        FilterDataManager filters;

        int indexcode;
        byte[] encode;

        System.Timers.Timer check_connect;
        System.Timers.Timer check_code;
        public User(int id, Socket socket)
        {
            info = new PlayerInfo();
            this.info.ID = id;
            this.client = socket;
            IPEndPoint endpoint = (IPEndPoint)socket.RemoteEndPoint;
            ip = endpoint.Address;
            port = endpoint.Port;
            isPing = true;
            info.RoomID = -1;
            info.TableID = -1;
           
        }
        public User(Socket socket)
        {            
            this.client = socket;
            IPEndPoint endpoint = (IPEndPoint)socket.RemoteEndPoint;
            ip = endpoint.Address;
            port = endpoint.Port;
            isPing = true;
        }
        void Init()
        {
            filters = new FilterDataManager();
            check_connect = new System.Timers.Timer(60000);
            check_connect.Elapsed += new System.Timers.ElapsedEventHandler(check_connect_Elapsed);
            check_code = new System.Timers.Timer(10000);
            check_code.Elapsed += new System.Timers.ElapsedEventHandler(check_code_Elapsed);
        }

        public override string ToString()
        {
            return string.Format("{0}|{1}|{2}", info.ID, info.NickName, info.RoomID);
        }
        public string Str_JoinRoom()
        {
            return string.Format("{0}|{1}", info.ID, info.NickName);
        }
        public string Str_OutRoom()
        {
            return string.Format("{0}", info.ID);
        }
        public void BeginCheckCode(YAuthentication authentication)
        {
            Init();
            indexcode = authentication.GetCode();
            encode = authentication.Calculate(indexcode);
            SendData(BitConverter.GetBytes(indexcode));
            check_code.Start();
            client.BeginReceive(buffer, 0, 2, SocketFlags.None, new AsyncCallback(OnSizeCodeReceive), client);
        }

        void OnSizeCodeReceive(IAsyncResult ar)
        {
            try
            {
                if (!ar.IsCompleted)
                {
                    Console.WriteLine("Send Size code Failed");
                    return;
                }
                client.EndReceive(ar);
                byte[] received = new byte[] { buffer[0], buffer[1] };
                SumSizeReceive = (int)BitConverter.ToInt16(received, 0);
                if (client.Connected)
                {
                    if (SumSizeReceive > 0)                 
                        client.BeginReceive(buffer, 2, SumSizeReceive, SocketFlags.None, new AsyncCallback(OnCodeReceive), client);          
                                        
                }
            }
            catch (System.Exception e)
            {
              
                ClientDisconnect();
            }
        }

        void OnCodeReceive(IAsyncResult ar)
        {
            try
            {
                if (!ar.IsCompleted)
                {
                    Console.WriteLine("Receive Error");
                    return;
                }
                SocketError error;
                int i = client.EndReceive(ar, out error);            
                if (i < 1)
                {
                    Console.WriteLine("Receive Error");
                    return;
                }
                SizeReceived += i;
                if (client.Connected)
                {
                    if (SizeReceived < SumSizeReceive)
                        client.BeginReceive(buffer, SizeReceived + 2, SumSizeReceive - SizeReceived, SocketFlags.None, new AsyncCallback(OnCodeReceive), client);
                    else
                    {                        
                        CheckCode();                                             
                    }
                }
            }
            catch (System.Exception e)
            { 

                ClientDisconnect();
            }
        }
        void CheckCode()
        {
            check_code.Stop();
            check_code = null;
            dataReceive = filters.ProcessDataReceive(buffer);
            if (Equals())
            {
                Console.WriteLine("Check code = " + indexcode.ToString() + "  OK");
                ResetSumReceive();
                BeginReceive();
            }
            else
            {
                Console.WriteLine("Check code = " + indexcode.ToString() + "  Failed");               
                ClientDisconnect();
            }
            
            
        }

        void check_code_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine("End Timer: Client will die >:) :))");
            check_code.Stop();
            check_code = null;
            client.Disconnect(false);
            if (XSocketDisconnected != null)
                    XSocketDisconnected(this, new XSocketDisconnectEventArgs(this));            
        }

        bool Equals()
        {
            if (dataReceive.Length != encode.Length)
                return false;
            for (int i = 0; i < dataReceive.Length;i++ )
            {
                if (dataReceive[i] != encode[i])
                    return false;
            }
            return true;
        }

        #region Receive Data

        public void BeginReceive()
        {           
            client.BeginReceive(buffer, 0, 2, SocketFlags.None, new AsyncCallback(OnSizeReceive), client);            
            StartCheckDisconnect();
        }

        int SumSizeReceive = 0;
        int SizeReceived = 0;
        void OnSizeReceive(IAsyncResult ar)
        {
            try
            {
                if (!ar.IsCompleted)
                {
                    Console.WriteLine("Send Size Failed");
                    return;
                }
                client.EndReceive(ar);
                StopCheckDisconnect();
                byte[] received = new byte[] { buffer[0], buffer[1] };
                SumSizeReceive = (int)BitConverter.ToInt16(received, 0);
                if (client.Connected)
                {
                    if (SumSizeReceive > 0)
                    {
                        client.BeginReceive(buffer, 2, SumSizeReceive, SocketFlags.None, new AsyncCallback(OnReceive), client);
                        StartCheckDisconnect();

                    }
                    else
                    {

                        client.BeginReceive(buffer, 0, 2, SocketFlags.None, new AsyncCallback(OnSizeReceive), client);
                        StartCheckDisconnect();

                    }
                }
            }
            catch (System.Exception e)
            {                
                ClientDisconnect();
               
            }
        }

        void OnReceive(IAsyncResult ar)
        {
            try
            {
                if (!ar.IsCompleted)
                {
                    Console.WriteLine("Receive Error");
                    return;
                }
                SocketError error;
                int i = client.EndReceive(ar, out error);
                StopCheckDisconnect();
                if (i < 1)
                {
                    Console.WriteLine("Receive Error");
                    return;
                }
                SizeReceived += i;
                if (client.Connected)
                {
                    if (SizeReceived < SumSizeReceive)
                    {

                        client.BeginReceive(buffer, SizeReceived + 2, SumSizeReceive - SizeReceived, SocketFlags.None, new AsyncCallback(OnReceive), client);
                        StartCheckDisconnect();

                    }
                    else
                    {
                        ProcessReceiveFullData();
                        ResetSumReceive();

                        client.BeginReceive(buffer, 0, 2, SocketFlags.None, new AsyncCallback(OnSizeReceive), client);
                        StartCheckDisconnect();

                    }
                }



            }
            catch (System.Exception e)
            {              
                ClientDisconnect();
            }
        }

        void ProcessReceiveFullData()
        {
            dataReceive = filters.ProcessDataReceive(buffer);
            if (XSocketReceive != null)
                XSocketReceive(client, new XSocketReciveEventArgs(dataReceive, this));
        }

        void ResetSumReceive()
        {
            SumSizeReceive = 0;
            SizeReceived = 0;
            buffer = new byte[1024];
        }
        #endregion

        #region SendData
        void SendData(byte[] data)
        {
            StopCheckDisconnect();
            dataSend = filters.ProcessDataSend(data);
            if (client.Connected)
                StartCheckDisconnect();
            client.BeginSend(dataSend, 0, dataSend.Length, SocketFlags.None, new AsyncCallback(OnSend), null);
        }

        public void SendMessage(MSG_GSM message,params object[] param)
        {
            //Console.WriteLine("Send Message: " + message);
            List<byte> Data = new List<byte>();
            Data.Add((byte)message);
            foreach (object obj in param)
            {
                Data.Add((byte)obj);
            }
            SendData(Data.ToArray());
        }
        public void SendMessage(MSG_GSM message,byte[] param)
        {
            //Console.WriteLine("Send Message: " + message);
            List<byte> Data = new List<byte>();
            Data.Add((byte)message);
            Data.AddRange(param);
            SendData(Data.ToArray());
        }


        void OnSend(IAsyncResult ar)
        {
            try
            {
                if (!ar.IsCompleted || !client.Connected)
                    Console.WriteLine("Send no complete");
                client.EndSend(ar);
                StopCheckDisconnect();
                if (client.Connected)
                    StartCheckDisconnect();
            }
            catch (System.Exception e)
            {
                
            }
        }
        #endregion


        int PingMe()
        {            
            return PingClient.PingHost(ip, port);
        }

        void StartCheckDisconnect()
        {
            //if (isPing == true)
               // check_connect.Start();
        }
        void StopCheckDisconnect()
        {
            check_connect.Stop();
        }


        void check_connect_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            StopCheckDisconnect();
            int i = PingMe();
            if (i == -1)
            {
                Console.WriteLine("#########   Error Algorithm Ping   ############");
                StartCheckDisconnect();
                return;
            }
            if (i == 4)
            {
                if (XSocketDisconnected != null)
                    XSocketDisconnected(client, new XSocketDisconnectEventArgs(this));
                
                return;
            }
            else
            {
                Console.WriteLine("#########   Ping Complete   ############");
                StartCheckDisconnect();
                Console.WriteLine("########     Continue Check Disconnect     #########");
            }

        }

        public void ClientDisconnect()
        {
            client.Disconnect(true);
            if (XSocketDisconnected != null)
                XSocketDisconnected(client, new XSocketDisconnectEventArgs(this));
        }
        public void StopAll()
        {
            check_connect.Stop();
        }

        public int User_ID
        {
            get { return info.ID; }
            set { info.ID = value; }
        }

        public string User_Name
        {
            get { return info.NickName; }
            set { info.NickName = value; }
        }

        public event XSocketReciveHandler XSocketReceive;
        public delegate void XSocketReciveHandler(object sender, XSocketReciveEventArgs args);
        public event XSocketDisconnectedHandler XSocketDisconnected;
        public delegate void XSocketDisconnectedHandler(object sender, XSocketDisconnectEventArgs args);
    }
}
